博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
js的导出Excel,Word,pdf的实现以及服务器端生成pdf的实现
阅读量:4053 次
发布时间:2019-05-25

本文共 16159 字,大约阅读时间需要 53 分钟。

 

今天无意找到了很久前的js导出excel功能,用了一下感觉不错,在网上看很多人做js导出excel,可是对表格线的导出excel总是头疼,我这里有一个简单的导出js,大家可以看看。

       这只是一个简单demo:

Html代码:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html> 
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" /> 
<title>测试导出Excel功能</title> 
<script language=javascript>  
function preview() {   
 window.clipboardData.setData("Text",document.all('table2').outerHTML);  
 //下面这行代码,最后一列的查看数据也会导出到Excel文件中
 //window.clipboardData.setData("Text",document.all('table1').outerHTML);  
 try {  
  var ExApp = new ActiveXObject("Excel.Application")  
  var ExWBk = ExApp.workbooks.add()  
  var ExWSh = ExWBk.worksheets(1)  
  ExApp.DisplayAlerts = false 
  ExApp.visible = true 
 } catch(e) {  
  alert("您的电脑没有安装Microsoft Excel软件!")  
  return false 
 }   
 ExWBk.worksheets(1).Paste;   
 }  
</script>

<body> 

<table id="table1" width="90%" border="0" align="center" cellpadding="0" cellspacing="0"> 
  <tr> 
    <td width="6%" height="27" align="center">序号</td> 
    <td width="10%" align="center">时间</td> 
    <td width="20%" align="center">单位</td> 
    <td width="18%" align="center">项目</td> 
    <td width="10%" align="center">结果等级</td> 
    <td width="10%" align="center">检查机关</td> 
    <td width="8%" align="center">记录人</td> 
    <td width="12%" align="center">记录时间</td> 
    <td width="6%" align="center">查看</td> 
  </tr> 
  <tr> 
    <td height="21" align="center">1</td> 
    <td align="center">1980-02-02</td> 
    <td align="center">武警总队</td> 
    <td align="center">安全用电检查</td> 
    <td align="center">2222222</td> 
    <td align="center">总部</td> 
    <td align="center">主席</td> 
    <td align="center">1980-02-02</td> 
    <td align="center"><a href="aqChakanShow.html">查看</a></td> 
  </tr> 
  <tr> 
    <td height="21" align="center">2</td> 
    <td align="center">1980-02-02</td> 
    <td align="center">武警总队</td> 
    <td align="center">安全用电检查</td> 
    <td align="center">2222222</td> 
    <td align="center">总部</td> 
    <td align="center">总理</td> 
    <td align="center">1980-02-02</td> 
    <td align="center"><a href="aqChakanShow.html">查看</a></td> 
  </tr> 
</table> 
<table id="table2" width="90%" border="0" align="center" cellpadding="0" cellspacing="0" style='visibility:hidden;'> 
  <tr> 
    <td width="6%" height="27" align="center">序号</td> 
    <td width="10%" align="center">时间</td> 
    <td width="20%" align="center">单位</td> 
    <td width="18%" align="center">项目</td> 
    <td width="10%" align="center">结果等级</td> 
    <td width="10%" align="center">检查机关</td> 
    <td width="8%" align="center">记录人</td> 
    <td width="12%" align="center">记录时间</td> 
  </tr> 
  <tr> 
    <td height="21" align="center">1</td> 
    <td align="center">1980-02-02</td> 
    <td align="center">武警总队</td> 
    <td align="center">安全用电检查</td> 
    <td align="center">2222222</td> 
    <td align="center">总部</td> 
    <td align="center">主席</td> 
    <td align="center">1980-02-02</td> 
  </tr> 
  <tr> 
    <td height="21" align="center">2</td> 
    <td align="center">1980-02-02</td> 
    <td align="center">武警总队</td> 
    <td align="center">安全用电检查</td> 
    <td align="center">2222222</td> 
    <td align="center">总部</td> 
    <td align="center">总理</td> 
    <td align="center">1980-02-02</td> 
  </tr> 
 </table> 
<table width="90%" align="center" border="0" cellpadding="0" cellspacing="0"> 
  <tr> 
    <td width="50%" height="30" align="right" valign="bottom" style="padding-right:10px;"><input type="submit" name="Submit2" οnclick="preview()" value="打印当前页" class="waikuang" ></td> 
  </tr> 
</table> 
</body> 
</html> 

 

这个js是根据table的id进行导出的,这样有个缺点:会将最后一列的“查看”进行导出excel输出。解决方法,在此页面再输出一个隐藏的table并给他标示,这个隐藏table只有数据,这样点击导出,只导出数据。方法繁重,希望有别的解决方法,如果有请指教。

注意这种方式的缺点:

这个是基于降低安全性的操作的,所以如果是基于内网应用的话还是不错的,并且还得安装Ofiice!

不能控制列宽,还得在excel里面手动去拉,用户体验不好

js导出excel看不出有啥需要的地方,在慢的客户端你都可以看到它一行行的填充,看着都难受。况且一般都是分页的,前段数据也不多,也导不全吧。jxl模板导出,要啥格式就有啥格式。

ActiveXObject在firefox下是没法用的,只适用于IE

 

 

 

 

 

 

javascript 客户端实现导出word、excel的小程序  

代码如下:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>
 <head>
  <title>testExport.html</title>
  <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
  <meta http-equiv="description" content="this is my page">
  <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  <!--<link rel="stylesheet" type="text/css" href="./styles.css">-->
 </head>
 <body>
  <table id="PrintA" width="100%" border="1" cellspacing="0"
   cellpadding="0" bgcolor="#61FF13">
   <TR style="text-align: center;">
    <TD>
     单元格A
    </TD>
    <TD>
     单元格A
    </TD>
    <TD>
     单元格A
    </TD>
    <TD>
     单元格A
    </TD>
   </TR>
   <TR>
    <TD colSpan=4 style="text-align: center;">
     <font color="BLUE" face="Verdana">单元格合并行A</FONT>
    </TD>
   </TR>
  </TABLE>
  <table id="PrintB" width="100%" border="1" cellspacing="0"
   cellpadding="0">
   <TR style="text-align: center;">
    <TD>
     单元格B
    </TD>
    <TD>
     单元格B
    </TD>
    <TD>
     单元格B
    </TD>
    <TD>
     单元格B
    </TD>
   </TR>
   <TR>
    <TD colSpan=4 style="text-align: center;">
     单元格合并行B
    </TD>
   </TR>
  </TABLE>
  <br />
  <input type="button" οnclick="javascript:AllAreaWord();"
   value="导出页面指定区域内容到Word">
  <input type="button" οnclick="javascript:AllAreaExcel();"
   value="导出页面指定区域内容到Excel">
  <input type="button" οnclick="javascript:CellAreaExcel();"
   value="导出表单单元格内容到Excel">
  
  <SCRIPT LANGUAGE="javascript">
    //指定页面区域内容导入Excel
    function AllAreaExcel()
    {
      var oXL = new ActiveXObject("Excel.Application");
      var oWB = oXL.Workbooks.Add();
      var oSheet = oWB.ActiveSheet; 
      var sel=document.body.createTextRange();
      sel.moveToElementText(PrintA);
      sel.select();
      sel.execCommand("Copy");
      oSheet.Paste();
      oXL.Visible = true;
    }
   
    //指定页面区域“单元格”内容导入Excel
    function CellAreaExcel()
    {
      var oXL = new ActiveXObject("Excel.Application");
      var oWB = oXL.Workbooks.Add();
      var oSheet = oWB.ActiveSheet;
      var Lenr = PrintA.rows.length;
      for (i=0;i<Lenr;i++) {
       var Lenc = PrintA.rows(i).cells.length;
       for (j=0;j<Lenc;j++) {
        oSheet.Cells(i+1,j+1).value = PrintA.rows(i).cells(j).innerText;
       }
      }
      oXL.Visible = true;
    }
   
    //指定页面区域内容导入Word
    function AllAreaWord()
    {
      var oWD = new ActiveXObject("Word.Application");
      var oDC = oWD.Documents.Add("",0,1);
      var oRange =oDC.Range(0,1);
      var sel = document.body.createTextRange();
      sel.moveToElementText(PrintA);
      sel.select();
      sel.execCommand("Copy");
      oRange.Paste();
      oWD.Application.Visible = true;
      //window.close();
    }
  </SCRIPT>
 </body>
</html>

 导出PDF的处理:

在Java世界,要想生成PDF,方案不少。最近一直在和这个东西打交道,所以简单做一个小结吧。

在此之前,先来勾画一下我心中比较理想的一个解决方案。在企业应用中,碰到的比较多的PDF的需求,可能是针对某个比较典型的具备文档特性的内容,导出成为PDF进行存档。由于我们现在往往使用一些开源框架,诸如ssh来构建我们的应用,所以我们相对熟悉的方案是针对具体的业务逻辑设计实体,使用开源框架来实现我们的业务逻辑。而PDF的导出,最好不要破坏现有的程序框架,甚至能复用我们业务逻辑层的代码。因为如果把PDF作为一种特殊的表现形式的话,实际上它有点类似模板。最佳的情况,是我们能够通过编写某种模板,把PDF的大概样子确定下来,然后把数据和模板做一次整合,得到最后的结果
带着这个目标,开始在网上搜索解决方案。也找到了一些方案,下面简单小结一下:
Jasper Report
看到的市面上采用的最多的方案,是Jasper Report。相关的文档也很多,不过很杂,需要完全掌握,我认为还是有些坡度和时间的。这个时间和坡度我认为主要来自于对iReport这个IDE的反复尝试,对里面的每个属性的摸索。
Jasper Report的设计思路,本身是不违反我上面所说的初衷的。因为我们的努力方向是先生成模板,然后得到数据,最后将两者整合得到结果。但是Jasper Report的问题在于,其生成模板的方式过于复杂,即使有IDE的帮助,我们还是需要对其中的众多规则有所了解才行,否则就会给调试带来极大的麻烦。
所以,我认为Jasper Report是一个半调子方案,这种强依赖于IDE进行可视化编辑的方式令我很不爽。同时,由此带来的诸多的限制,相信也让很多使用者颇为头疼。在经历了一番痛苦的挣扎后,决定放弃使用这种方案。
iText
其实Jasper Report是基于iText的。于是有的人会说,那么直接使用iText不是一种倒退么?的确,直接使用iText似乎就需要直接使用原生的API进行编程了。不过幸好iText其实提供了一些方便的API,通过使用这些API,我们可以直接将HTML代码转化成iText可识别的Document对象,从而导出PDF文档。

Java代码:
import java.io.FileOutputStream;import java.io.FileReader;import java.util.ArrayList;import com.lowagie.text.Document;import com.lowagie.text.Element;import com.lowagie.text.html.simpleparser.HTMLWorker;import com.lowagie.text.html.simpleparser.StyleSheet;import com.lowagie.text.pdf.PdfWriter;public class MainClass {  public static void main(String[] args) throws Exception {    Document document = new Document();    StyleSheet st = new StyleSheet();    st.loadTagStyle("body", "leading", "16,0");    PdfWriter.getInstance(document, new FileOutputStream("html2.pdf"));    document.open();    ArrayList p = HTMLWorker.parseToList(new FileReader("example.html"), st);    for (int k = 0; k < p.size(); ++k)      document.add((Element) p.get(k));    document.close();  }}

这是从网上找到的一个例子。从代码中,我们可以看到,iText本身提供了一个简单的HTML的解析器,它可以把HTML转化成我们需要的PDF的document。
有了这个东西,基本上我的目标就能达成一大半了。接下来我的任务就是根据实际情况去编写HTML代码,然后扔进这个方法,就OK了。而真正的HTML代码,我们则可以在这里使用真正的模板技术,Freemarker或者Velocity去生成我们所需要的内容。当然,这已经是我们熟门熟路的东西了。
正当我觉得这个方案基本能符合我的要求的时候,我也同样找到了它的很多弱项:
1. 无法识别很多HTML的tag和attribute(应该是iText的HTMLParser不够强大)
2. 无法识别CSS
如果说第一点我还可以勉强接受的话,那么第二点我就完全不能接受了。无法识别简单的CSS,就意味着HTML失去了最基本的活力,也无法根据实际要求调整样式。
所以这种方案也必然无法成为我的方案。
flying sauser
在这种情况下,我几乎已经燃起了自己编写一个支持CSS解析的HTML Parser的想法。幸好,在一个非常偶然的情况下,我在google中搜到了这样一个开源项目,它能够满足我的一切需求。这就是flying sauser,项目主页是:
项目的首页非常吸引人:An XML/XHTML/CSS 2.1 Renderer。这不正是我要的东西么?
仔细再看里面的文档:

引用
Flying Saucer is an XML/CSS renderer, which means it takes XML files as input, applies formatting and styling using CSS, and generates a rendered representation of that XML as output. The output may go to the screen (in a GUI), to an image, or to a PDF file. Because we believe most people will be interested in re-using their knowledge of web layout, our main target for content is XHTML 1.0 (strict), an XML document format that standardizes HTML.

完美了。这东西能解析HTML和CSS,而且能输出成image,PDF等格式。哇!我们来看看sample代码(代码丑陋,不过已经能说明问题了):

Java代码:
/* * ITextRendererTest.java * * Copyright 2009 Shanghai TuDou.  * All rights reserved. */package itext;import java.io.File;import java.io.FileOutputStream;import java.io.OutputStream;import org.xhtmlrenderer.pdf.ITextFontResolver;import org.xhtmlrenderer.pdf.ITextRenderer;import com.lowagie.text.pdf.BaseFont;/**  * TODO class description *  * * @author pcwang * * @version 1.0, 上午11:03:26  create $Id$ */public class ITextRendererTest {	public static void main(String[] args) throws Exception {		String inputFile = "conf/template/test.html";        String url = new File(inputFile).toURI().toURL().toString();        String outputFile = "firstdoc.pdf";        OutputStream os = new FileOutputStream(outputFile);        ITextRenderer renderer = new ITextRenderer();        renderer.setDocument(url);        // 解决中文支持问题        ITextFontResolver fontResolver = renderer.getFontResolver();        fontResolver.addFont("C:/Windows/Fonts/arialuni.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);        // 解决图片的相对路径问题        renderer.getSharedContext().setBaseURL("file:/D:/Work/Demo2do/Yoda/branch/Yoda%20-%20All/conf/template/");                renderer.layout();        renderer.createPDF(os);                os.close();	}}

运行,成功!实在太简单了!API帮你完成了一切!
有了这个东西,我们就可以将PDF的生成流程变成这样:
1) 编写Freemarker或者Velocity模板,打造HTML,勾画PDF的样式(请任意使用CSS)
2) 在你的业务逻辑层引入Freemarker的引擎或者Velocity的引擎,并将业务逻辑层中可以获取的数据和模板,使用引擎生成最终的内容
3) 将我上面的sample代码做简单封装后,调用,生成PDF
这样,我想作为一个web程序员来说,上面的3点,都不会成为你的绊脚石。你可以轻松驾驭PDF了。
在Flying Saucer的官方文档中,有一些Q&A,可以解决读者们大部分的问题。包括PDF的字体、PDF的格式、Image如何处理等等。大家可以尝试着去阅读。

 

 

下面是我在自己项目中的实现代码:

public void viewExportPDF(ActionMapping mapping, ActionForm form,			HttpServletRequest request, HttpServletResponse response)			throws Exception {		ServletContext sc = request.getSession().getServletContext();		String rootpath = sc.getRealPath(""); //值为D:\apache-tomcat-6.0.26\webapps\webmonitor		//把路径中的反斜杠转成正斜杠		rootpath = rootpath.replaceAll("\\\\", "/"); //值为D:/apache-tomcat-6.0.26/webapps/webmonitor		//临时存储目录		String pdfPathName = rootpath + "/WebReport.pdf";		ArrayList
list = new ArrayList
(); for(int i=0;i
list, String pdfPathName, HttpServletRequest request, HttpServletResponse response) throws Exception { /** * 用rootpath指定目录也可以生成pdf文件,只不过不能在myeclipse的左边导航窗口中看不到而已 * 左边导航窗口对应C盘目录下的workspace目录下程序 * 用rootpath指定的目录是D盘Tomcat目录 */ ServletContext sc = request.getSession().getServletContext(); String rootpath = sc.getRealPath(""); //值为D:\apache-tomcat-6.0.26\webapps\webmonitor //把路径中的反斜杠转成正斜杠 rootpath = rootpath.replaceAll("\\\\", "/"); //值为D:/apache-tomcat-6.0.26/webapps/webmonitor boolean flag = false; String outputFile = pdfPathName; //指定目录导出文件 OutputStream os = new FileOutputStream(outputFile); ITextRenderer renderer = new ITextRenderer(); StringBuffer html = new StringBuffer(); //组装成符合W3C标准的html文件,否则不能正确解析 html.append(""); html.append("") .append("") .append("
") .append("
") .append("
") .append("
") .append("") .append(""); html.append("
"); html.append("

统计报表

"); for(int i=0;i
" + list.get(i) + ""); } html.append("
"); html.append(""); try { renderer.setDocumentFromString(html.toString()); // 解决图片的相对路径问题,图片路径必须以file开头 renderer.getSharedContext().setBaseURL("file:/" + rootpath); renderer.layout(); renderer.createPDF(os); os.close(); flag = true; } catch (Exception e) { flag = false; e.printStackTrace(); } return flag; }

其中这一段代码是用来实现导出时打开另存为窗口功能的:

OutputStream out = response.getOutputStream();	byte by[] = new byte[1024];	File fileLoad = new File(pdfPathName);	response.reset();	response.setContentType("application/pdf");	response.setHeader("Content-Disposition",		"attachment; filename=WebReport.pdf");	long fileLength = fileLoad.length();	String length1 = String.valueOf(fileLength);	response.setHeader("Content_Length", length1);	FileInputStream in = new FileInputStream(fileLoad);	int n;	while ((n = in.read(by)) != -1) {		out.write(by, 0, n);	}	in.close();	out.flush();

注意要实现打开另存为窗口,必须满足两个条件:

1.导入commons-upload.jar包

2.通过表单提交请求(现在我也搞不懂为什么)

 

用Servlet实现的下载窗口实现代码:

package com.test;import java.io.IOException;import java.io.OutputStream;import javax.servlet.ServletContext;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.xhtmlrenderer.pdf.ITextFontResolver;import org.xhtmlrenderer.pdf.ITextRenderer;import com.lowagie.text.pdf.BaseFont;public class Html2PdfServlet extends HttpServlet {	private static final long serialVersionUID = 1L;	public void doGet(HttpServletRequest request, HttpServletResponse response)		throws ServletException, IOException {		//pageContext.getServletContext().getRealPath("/")		ServletContext sc = request.getSession().getServletContext();		String path = sc.getRealPath(""); //值为D:\apache-tomcat-6.0.26\webapps\createpdf		System.out.println("原path: " + path);		//把路径中的反斜杠转成正斜杠		path = path.replaceAll("\\\\", "/"); //值为D:/apache-tomcat-6.0.26/webapps/createpdf		System.out.println(path);				String path2 = sc.getRealPath("/");		System.out.println("path2: " + path2);				System.out.println(Thread.currentThread().getContextClassLoader().getResource(""));				System.out.println("request.getRequestURI: " + request.getRequestURI());		//获取使用的端口号		System.out.println(request.getLocalPort());				String path3 = request.getContextPath();		String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path3+"/";				System.out.println("basepath: " + basePath);						response.setContentType("application/pdf");		//response.setHeader("Content-Disposition", "attachment; filename=WebReport.pdf");		response.setHeader("Content-Disposition", "inline; filename=WebReport.pdf");        		StringBuffer html = new StringBuffer();		//组装成符合W3C标准的html文件,否则不能正确解析		html.append("");		html.append("")		.append("")		.append("
") .append("") .append("") .append("") .append(""); html.append("

统计报表

"); html.append("
"); html.append("
"); html.append("
"); html.append(""); // parse our markup into an xml Document try { ITextRenderer renderer = new ITextRenderer(); /** * 引入了新的jar包,不用再导入字体了 ITextFontResolver fontResolver = renderer.getFontResolver(); fontResolver.addFont("C:/Windows/fonts/simsun.ttc", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); */ renderer.setDocumentFromString(html.toString()); // 解决图片的相对路径问题 //renderer.getSharedContext().setBaseURL("file:/C:/Documents and Settings/dashan.yin/workspace/createpdf/WebRoot/images"); //renderer.getSharedContext().setBaseURL("file:/D:/apache-tomcat-6.0.26/webapps/createpdf/images"); renderer.getSharedContext().setBaseURL("file:/" + path + "/images"); renderer.layout(); OutputStream os = response.getOutputStream(); renderer.createPDF(os); os.close(); } catch (Exception e) { e.printStackTrace(); } } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); }}

主要是这句代码:

response.setHeader("Content-Disposition", "attachment; filename=WebReport.pdf");

告诉浏览器是以附件的形式

转载地址:http://kltci.baihongyu.com/

你可能感兴趣的文章
servlet中请求转发(forword)与重定向(sendredirect)的区别
查看>>
Spring4的IoC和DI的区别
查看>>
springcloud 的eureka服务注册demo
查看>>
eureka-client.properties文件配置
查看>>
MODULE_DEVICE_TABLE的理解
查看>>
platform_device与platform_driver
查看>>
platform_driver平台驱动注册和注销过程(下)
查看>>
.net强制退出主窗口的方法——Application.Exit()方法和Environment.Exit(0)方法
查看>>
c# 如何调用win8自带的屏幕键盘(非osk.exe)
查看>>
build/envsetup.sh 简介
查看>>
Android framework中修改或者添加资源无变化或编译不通过问题详解
查看>>
linux怎么切换到root里面?
查看>>
linux串口操作及设置详解
查看>>
安装alien,DEB与RPM互换
查看>>
编译Android4.0源码时常见错误及解决办法
查看>>
Android 源码编译make的错误处理
查看>>
linux环境下C语言中sleep的问题
查看>>
ubuntu 12.04 安装 GMA3650驱动
查看>>
新版本的linux如何生成xorg.conf
查看>>
xorg.conf的编写
查看>>